﻿using UnityEngine;
using System.Collections.Generic;
using TTGame;
using System;

/*
 * ObjectManager
 *
 *
 *
 * 依赖：
 *
 * ！不写重复代码！
 * @author TTun
 * @date 7/12/2017 8:45:37 PM
 */
namespace TTGameEngine {

public enum LayerName {
    Default,
    hero,
    enemy,
    friend,
    SkillingHero, //临时Layer。放大招时镜头高亮效果会有layer变换，hero\friend->ObjCamera。layer为ObjCamera的对象，当做hero或者friend看
    HeroEffect, //玩家的特效单独标记Layer。用于FPS时方便隐藏。
}

/// <summary>
/// 可选择目标的类型（按照敌对关系划分）
/// 顺序和CampRelation对应。不能随便修改顺序。
/// </summary>
public enum TargetSelectType {
    Self,  //自己。表示自己这单单一个对象。不包括其他相同对象类型的对象。
    Friend, //友方。阵营友好的对象。包括同一对象类型的对象。包括自己。
    Enemy, //敌方
    Neutral, //中立
    Count,
}


public enum ObjPrefabPathType {
    Enemy_Prefab_Path,
    Role_Prefab_Path,
}

/// <summary>
/// 游戏内对象可分为多个阵营。每个阵营之间有敌对、友好、中立关系
/// </summary>
public enum PuppetCampID {
    None = -1,
    Hero = 0,
    Enemy,
    FriendNPC,  //友方NPC
    NeutralNPC, //中立NPC
    Count,
}
/// <summary>
/// 阵营关系没有Self，自己和自己阵营有可能是多个人物。只有一个人物自己才是Self。
/// 顺序和TargetSelectType对应。不能随便修改顺序。
/// </summary>
public enum CampRelation {
    Friendly,
    Hostile,
    Neutral,
    Count,
}
/// <summary>
/// 游戏对象分类型。
/// 阵营、layer根据对象类型设置。
/// </summary>
public enum ObjType {
    None = -1,
    PlayerSelf,
    FriendPlayer,
    EnemyPlayer,
    Monster,   //敌方怪物
    Boss,       //boss单独分类
    FriendNPC,
    SkillingPlayer, //一个临时的ObjType。正在放大招的玩家/友方，有单独的layerID(HeroCamera)，所以单独加一个ObjType，方便处理。
    Count,
}
/// <summary>
/// 游戏对象分类型。
/// 阵营、layer根据对象类型设置。
/// 游戏内对象可分为多个阵营。每个阵营之间有敌对、友好、中立关系
/// </summary>
public class ObjTypeConfig {
    public ObjType objType;
    public PuppetCampID objCampID;
    public LayerName objLayerName;
    //[CampRelation] = LayerMask
    //所有[友好/敌对/中立]对象的layerMask
    public int[] campLayerMasks = new int[(int)CampRelation.Count];
    //[CampRelation] = ObjTypeConfig[]
    //所有[友好/敌对/中立]对象的ObjTypeConfig
    public List<ObjTypeConfig>[] campRelaConfigs = new List<ObjTypeConfig>[(int)CampRelation.Count];

    public ObjTypeConfig(ObjType type, PuppetCampID camp, LayerName layer) {
        objType = type;
        objCampID = camp;
        objLayerName = layer;
    }
}

public class ObjectManager : MonoBehaviour {
    static ObjectManager m_instance;

    Dictionary<string, Puppet> m_objs = new Dictionary<string, Puppet>();
    List<Puppet>[] m_objCampDict = new List<Puppet>[(int)PuppetCampID.Count];

    //Dictionary<string, Puppet> m_deadobjs = new Dictionary<string, Puppet>();

    //受伤框搜集
    Dictionary<Collider, Puppet> m_puppetColliders = new Dictionary<Collider, Puppet>();

    public ObjTypeConfig[] ObjConfig = {
        new ObjTypeConfig(ObjType.PlayerSelf,   PuppetCampID.Hero,  LayerName.hero),
        new ObjTypeConfig(ObjType.FriendPlayer, PuppetCampID.Hero,  LayerName.friend),
        new ObjTypeConfig(ObjType.EnemyPlayer,  PuppetCampID.Enemy, LayerName.enemy),
        new ObjTypeConfig(ObjType.Monster,      PuppetCampID.Enemy, LayerName.enemy),
        new ObjTypeConfig(ObjType.Boss,         PuppetCampID.Enemy, LayerName.enemy),
        new ObjTypeConfig(ObjType.FriendNPC,    PuppetCampID.Hero,  LayerName.friend),
        new ObjTypeConfig(ObjType.SkillingPlayer, PuppetCampID.Hero,  LayerName.SkillingHero),
    };

    //CampRelation[B,A] A<->B阵营关系。
    CampRelation[,] m_campRelations = {
        //阵营A:Self             Enemy                   友方NPC                 中立NPC
        {CampRelation.Friendly, CampRelation.Hostile,   CampRelation.Friendly,  CampRelation.Neutral},  //阵营B:Self
        {CampRelation.Hostile,  CampRelation.Friendly,  CampRelation.Hostile,   CampRelation.Neutral},  //阵营B:Enemy
        {CampRelation.Friendly, CampRelation.Hostile,   CampRelation.Friendly,  CampRelation.Neutral},  //阵营B:友方NPC
        {CampRelation.Friendly, CampRelation.Hostile,   CampRelation.Neutral,   CampRelation.Friendly}, //阵营B:中立NPC
    };

    //<所有CampID<敌对/友好/中立的<CampIDs>>>
    List<List<List<PuppetCampID>>> m_campRelationCampIDs = new List<List<List<PuppetCampID>>>();

    public static ObjectManager Share() {
        if(m_instance == null) {
            GameObject obj = new GameObject("ObjectManager");
            m_instance = obj.AddComponent<ObjectManager>();
            m_instance.init();
        }
        return m_instance;
    }

    void init() {
        //所有[友好/敌对/中立]对象的ObjTypeConfig 和 layerMask
        //添加考虑ObjCamera临时Layer
        for(int i = 0; i < ObjConfig.Length; i++) {
            ObjTypeConfig config = ObjConfig[i];
            for(int objTypeIdx = 0; objTypeIdx < ObjConfig.Length; objTypeIdx++) {
                if(objTypeIdx == i) continue;
                ObjTypeConfig targetConfig = ObjConfig[objTypeIdx];
                CampRelation campRelation = m_campRelations[(int)config.objCampID, (int)targetConfig.objCampID];
                int campRelationIdx = (int)campRelation;
                config.campLayerMasks[campRelationIdx] |= GetObjLayerMask((ObjType)objTypeIdx);
                if(config.campRelaConfigs[campRelationIdx] == null) {
                    config.campRelaConfigs[campRelationIdx] = new List<ObjTypeConfig>();
                }
                config.campRelaConfigs[campRelationIdx].Add(targetConfig);
            }
        }
        //所有CampID敌对/友好/中立的CampID
        m_campRelationCampIDs.Clear();
        for(int campIdx = 0; campIdx < (int)PuppetCampID.Count; campIdx++) {
            List<List<PuppetCampID>> campRelaCampIDs = new List<List<PuppetCampID>>();
            m_campRelationCampIDs.Add(campRelaCampIDs);
            PuppetCampID campID = (PuppetCampID)campIdx;
            for(int relaIdx = 0; relaIdx < (int)CampRelation.Count; relaIdx++) {
                List<PuppetCampID> relaCampIDs = new List<PuppetCampID>();
                campRelaCampIDs.Add(relaCampIDs);
                CampRelation relation = (CampRelation)relaIdx;
                for(int enumCampIdx = 0; enumCampIdx < (int)PuppetCampID.Count; enumCampIdx++) {
                    if(m_campRelations[campIdx, enumCampIdx] == relation) {
                        relaCampIDs.Add((PuppetCampID)enumCampIdx);
                    }
                }
            }
        }

        for(int i = 0; i < (int)PuppetCampID.Count; i++) {
            m_objCampDict[i] = new List<Puppet>();
        }

    }

    void Update() {
        //campShareEnemyList.Clear();
    }

    #region 对象管理
    public string GetPrefabRootPath(ObjPrefabPathType prefabPathType) {
        string rootPath = "";
        switch(prefabPathType) {
            case ObjPrefabPathType.Enemy_Prefab_Path:
                rootPath = GameConstant.PrefabPath_Enemy;
                break;
            case ObjPrefabPathType.Role_Prefab_Path:
                rootPath = GameConstant.PrefabPath_Role;
                break;
        }
        return rootPath;
    }

    //isAdd。 暂不加入对象管理列表，等对象数据（特别是GID）设置OK了，再加入列表。
    public Puppet CreateObj(ObjType objType, GameObject prefab, Vector3 pos, Transform parentTF = null, bool isAdd = true) {
        if(prefab == null) return null;
        Puppet obj = null;
        GameObject f = ObjectRecycler.Instance.InstantiatePrefab(prefab, pos, Quaternion.identity);
        obj = f.GetComponent<Puppet>();
        obj.ResetObj();
        obj.ObjTypeID = objType;
        if(isAdd) AddObject(obj);
        f.transform.parent = parentTF;

        return obj;
    }

    public GameObject GetObjPrefab(string prefabName, ObjPrefabPathType prefabPathType) {
        return GameObjectLoader.Ins.GetPrefabObj(GetPrefabRootPath(prefabPathType) + prefabName) as GameObject;
    }


    public Puppet CreateObj(ObjType objType, string prefabName, Vector3 pos, ObjPrefabPathType prefabPathType, Transform parentTF = null, bool isAdd = true) {
        GameObject _prefab = GetObjPrefab(prefabName, prefabPathType);
        Puppet obj = CreateObj(objType, _prefab, pos, parentTF, isAdd);
        if(obj == null) {
            DebugUtil.LogErrorFormat("[ObjMgr] 对象创建失败。prefabPath:[{0}]", GameConstant.PrefabPath_Role + prefabName);
        }
        return obj;
    }

    //puppet的Awake时添加对象管理器，方便直接从资源拖动实例化puppet。
    public void AddObject(Puppet obj) {
        if(m_objs.ContainsKey(obj.GetGID())) {
            DebugUtil.LogErrorFormat("[ObjMgr] obj[{0}] has existed!", obj.nameEn);
            return;
        }
        m_objs.Add(obj.GetGID(), obj);
        obj.RegistEvent_DeadRelease(OnPuppetDeadRelease);
        m_objCampDict[(int)obj.CampID].Add(obj);

        registCollider(obj);
    }

    public void RemoveObject(Puppet obj) {
        m_objs.Remove(obj.GetGID());
        List<Puppet> objList = m_objCampDict[(int)obj.CampID];
        objList.Remove(obj);
        removeCollider(obj);

        ObjectRecycler.Instance.Deactivate(obj.gameObject);
    }

    void OnPuppetDeadRelease(Puppet deadObj) {
        RemoveObject(deadObj);
    }
    #endregion

    public Puppet GetObjectWithGID(string objGID) {
        Puppet p = null;
        m_objs.TryGetValue(objGID, out p);
        return p;
    }

    public Puppet GetObjectWithTouch(Vector3 touchPos, float size) {
        for(var ite = m_objs.GetEnumerator(); ite.MoveNext();) {
            Puppet obj = ite.Current.Value;
            if(obj != null && (obj.Pos - touchPos).sqrMagnitude < size * size) {
                return obj;
            }
        }
        return null;
    }

    public List<Puppet> GetCampObjList(PuppetCampID campID) {
        return m_objCampDict[(int)campID];
    }

    public void registCollider(Puppet obj) {
        Collider[] cols = obj.gameObject.GetComponentsInChildren<Collider>();

        for(int i = 0; i < cols.Length; i++) {
            m_puppetColliders.Add(cols[i], obj);
        }
    }
    public void removeCollider(Puppet obj) {
        Collider[] cols = obj.gameObject.GetComponentsInChildren<Collider>();

        for(int i = 0; i < cols.Length; i++) {
            m_puppetColliders.Remove(cols[i]);
        }
    }

    public Puppet GetPuppetByCollider(Collider col) {
        Puppet obj = null;
        m_puppetColliders.TryGetValue(col, out obj);
        return obj;
    }

    #region 对象配置信息
    public CampRelation GetCampRelation(PuppetCampID campA, PuppetCampID campB) {
        return m_campRelations[(int)campB, (int)campA];
    }

    /// <summary>
    /// 与【阵营】的指定【关系】的所有阵营
    public List<PuppetCampID> GetRelationCampIDs(PuppetCampID camp, CampRelation relation) {
        return m_campRelationCampIDs[(int)camp][(int)relation];
    }

    public ObjTypeConfig GetObjTypeConfig(ObjType objtype) {
        return ObjConfig[(int)objtype];
    }

    //与【对象类型】的指定【关系】的所有对象类型
    public List<ObjTypeConfig> GetCampRelationConfigs(ObjType objtype, CampRelation relation) {
        return ObjConfig[(int)objtype].campRelaConfigs[(int)relation];
    }

    public PuppetCampID GetObjCampID(ObjType objtype) {
        return ObjConfig[(int)objtype].objCampID;
    }

    //【对象类型】对应的LayerID [0...31]。
    public int GetObjLayerMask(ObjType objtype) {
        return 1 << GetObjLayerID(objtype);
    }
    public int GetObjLayerID(ObjType objtype) {
        return LayerMask.NameToLayer(ObjConfig[(int)objtype].objLayerName.ToString());
    }

    //与我的【阵营】【敌对/友好/中立】的所有阵营的LayerMask。
    public int GetObjCampRelationLayerMask(ObjType objtype, CampRelation campRelation) {
        return ObjConfig[(int)objtype].campLayerMasks[(int)campRelation];
    }

    /// <summary>
    /// 将某对象的[目标类型]转化为具体的[LayerMask]，用于碰撞检测
    /// TargetSelectType -> LayerMask
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="targetType"></param>
    public LayerMask GetObjLayerMask(TargetTypeID targetType, ObjType objtype) {
        int layerMask = 0;

        //自己。表示自己这单单一个对象。不包括其他相同对象类型的对象。
        //友方。阵营友好的对象。包括同一对象类型的对象。包括自己。
        if(targetType.CheckMaskWithID((int)TargetSelectType.Self) || targetType.CheckMaskWithID((int)TargetSelectType.Friend)) {
            layerMask |= GetObjLayerMask(objtype);
        }
        for(int i = (int)TargetSelectType.Friend; i < (int)TargetSelectType.Count; i++) {
            if(targetType.CheckMaskWithID(i)) {
                layerMask |= GetObjCampRelationLayerMask(objtype, SelectType2CampRelation((TargetSelectType)i));
            }
        }

        return (LayerMask)layerMask;
    }

    /// <summary>
    /// 阵营关系  -> 目标类型
    /// XXX      ->  Self  //无法判断，需要额外处理。
    /// Friendly -> Friend
    /// hostile  ->  Enemy
    /// Neu      ->  Neu
    /// </summary>
    /// <param name="relation"></param>
    /// <returns></returns>
    public static TargetSelectType CampRelation2SelectType(CampRelation relation) {
        return (TargetSelectType)((int)relation + 1);
    }

    /// <summary>
    /// 目标类型 -> 阵营关系
    /// Self -> Friendly
    /// Friend -> Friendly
    /// Enemy  -> hostile
    /// Neu    -> Neu
    /// </summary>
    /// <param name="selectType"></param>
    /// <returns></returns>
    public static CampRelation SelectType2CampRelation(TargetSelectType selectType) {
        if(selectType == TargetSelectType.Self) {
            return CampRelation.Friendly;
        }
        return (CampRelation)((int)selectType - 1);
    }
    #endregion

    public void GetObjsWithSelectorResult(SkillSelector selector, ObjType objType, List<Puppet> aObjList) {
        if(selector.SelectorState != SelectorStateID.SelectOK) {
            DebugUtil.LogErrorFormat("[ObjMgr] Skill Selector not finished. state:[{0}]", selector.SelectorState.ToString());
            return;
        }

        SkillSelectorType selType = selector.SelectorType;
        if(selType == SkillSelectorType.Lock) {
            Puppet selectObj = GetObjectWithGID(selector.ResultLockObjGID);
            if(selectObj != null) {
                aObjList.Add(selectObj);
            }
        } else {
            List<Puppet> tmpCampObjList = null;
            //遍历敌对阵营
            var RelationConfigs = GetCampRelationConfigs(objType, CampRelation.Hostile);
            for(int i = 0; i < RelationConfigs.Count; i++) {
                PuppetCampID enemyCampID = RelationConfigs[i].objCampID;
                tmpCampObjList = GetCampObjList(enemyCampID);
                if(tmpCampObjList != null) {
                    for(int j = 0; j < tmpCampObjList.Count; j++) {
                        if(selector.IsInRange(tmpCampObjList[j].objTF.position)) {
                            aObjList.Add(tmpCampObjList[j]);
                        }
                    }
                }
            }

        }
    }

    #region 选取目标策略
    List<Puppet> tObjList = new List<Puppet>();
    /// <summary>
    /// 条件：
    /// 一个、最近的、活着的、敌对目标
    ///
    /// </summary>
    /// <param name="campID"></param>
    public Puppet Select_AliveNearEnemyObj(Puppet attacker) {
        tObjList.Clear();
        getCampRelationObjList(tObjList, attacker.CampID, CampRelation.Hostile);
        if(tObjList.Count == 0) {
            return null;
        }
        Puppet target = tObjList.objNearSortAscending(attacker.objTF.position).objSelectAlive();
        tObjList.Clear();
        return target;
    }

    //同一个阵营共用的敌人列表。每帧重新添加。
    Dictionary<ObjType, List<Puppet>> campShareEnemyList = new Dictionary<ObjType, List<Puppet>>();
    void getCampRelationObjList(List<Puppet> objList, PuppetCampID aCampID, CampRelation relation) {
        List<PuppetCampID> relaCampIDs = GetRelationCampIDs(aCampID, relation);
        for(int i = 0; i < relaCampIDs.Count; i++) {
            PuppetCampID campID = relaCampIDs[i];
            objList.AddRange(GetCampObjList(campID));
        }
    }

    /// <summary>
    /// 条件：
    /// 从阵营共用的列表中选取
    /// 一个、最近的、活着的、敌对目标
    /// 选完后目标从列表剔除。
    ///
    /// </summary>
    /// <param name="campID"></param>
    public Puppet Select_AliveNearEnemyObjWithCull(Puppet attacker) {
        ObjType atkObjType = attacker.ObjTypeID;
        List<Puppet> objList = null;
        campShareEnemyList.TryGetValue(atkObjType, out objList);
        if(objList == null) {
            objList = new List<Puppet>();
            getCampRelationObjList(objList, attacker.CampID, CampRelation.Hostile);
            campShareEnemyList.Add(atkObjType, objList);
        }

        if(objList.Count == 0) {
            return null;
        }
        Puppet target = objList.objNearSortAscending(attacker.objTF.position).objSelectAlive();
        objList.Remove(target);
        return target;
    }

    /// <summary>
    ///  条件：
    /// 一个、最近的、活着的、敌对目标。 除了某个对象以外。
    ///
    /// </summary>
    /// <param name="attacker"></param>
    /// <param name="exlusionObj"></param>
    /// <param name="isAllowOnlyExlusionObj">true:如果剩下的选择只有exlusionObj，则返回exlusionObj</param>
    /// <returns></returns>
    public Puppet Select_AliveNearEnemyObjWithExlusion(Puppet attacker, Puppet exlusionObj, bool isAllowOnlyExlusionObj = true) {
        tObjList.Clear();
        getCampRelationObjList(tObjList, attacker.CampID, CampRelation.Hostile);
        if(tObjList.Count == 0) {
            return null;
        }
        tObjList.Remove(exlusionObj);
        if(tObjList.Count == 0 && isAllowOnlyExlusionObj) {
            return exlusionObj;
        }
        Puppet target = tObjList.objNearSortAscending(attacker.objTF.position).objSelectAlive();
        tObjList.Clear();
        return target;
    }

    #endregion

}
}